package com.tengfei.main.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tengfei.common.core.domain.PageQuery;
import com.tengfei.common.core.domain.R;
import com.tengfei.common.core.page.TableDataInfo;
import com.tengfei.common.exception.ServiceException;
import com.tengfei.common.helper.LoginHelper;
import com.tengfei.main.course.domain.*;
import com.tengfei.main.course.mapper.*;
import com.tengfei.main.plan.domain.Plan;
import com.tengfei.main.plan.domain.PlanCourses;
import com.tengfei.main.plan.domain.PlanUsers;
import com.tengfei.main.plan.domain.UsersCourse;
import com.tengfei.main.plan.mapper.PlanCoursesMapper;
import com.tengfei.main.plan.mapper.PlanMapper;
import com.tengfei.main.plan.mapper.PlanUsersMapper;
import com.tengfei.main.plan.mapper.UserCoursesMapper;
import com.tengfei.main.user.domain.SearchEntity;
import com.tengfei.main.user.domain.bo.course.CourseProgressBo;
import com.tengfei.main.user.domain.vo.course.*;
import com.tengfei.main.user.service.IUserPlanService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author feige
 * @version v1.0
 * @date 2022-08-09-17:07
 * @description
 */

@Service
public class UserPlanServiceServiceImpl implements IUserPlanService {

    @Resource
    private PlanUsersMapper planUsersMapper;
    @Resource
    private PlanMapper planMapper;
    @Resource
    private PlanCoursesMapper planCoursesMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private ChapterMapper chapterMapper;
    @Resource
    private ChapterVideoMapper chapterVideoMapper;
    @Resource
    private UserCoursesMapper userCoursesMapper;
    @Resource
    private VideoMapper videoMapper;
    @Resource
    private ChapterResMapper chapterResMapper;
    @Resource
    private ResMapper resMapper;

    /**
     * 用户学习计划列表
     *
     * @return
     */
    @Override
    public List<UserPlanVo> planList() {
        // 获取用户Id
        Long userId = LoginHelper.getUserId();
        // 通过id查询用户学习计划列表
        List<PlanUsers> planUsers = planUsersMapper.selectList(new LambdaQueryWrapper<PlanUsers>()
                .eq(PlanUsers::getUserId, userId));
        List<UserPlanVo> userPlanVos = new ArrayList<>();
        planUsers.forEach(planUser -> {
            UserPlanVo userPlanVo = new UserPlanVo();
            // 查询学习计划
            Plan plan = planMapper.selectById(planUser.getPlanId());
            userPlanVo.setPlanId(plan.getPlanId());
            userPlanVo.setPlanName(plan.getPlanName());
            // 查询进度
            // 查询学习计划下课程id列表
            List<Long> courseIds = planCoursesMapper.selectList(new LambdaQueryWrapper<PlanCourses>()
                    .eq(PlanCourses::getPlanId, plan.getPlanId()))
                    .stream().map(planCourses -> planCourses.getCourseId())
                    .collect(Collectors.toList());
            // 总视频数
            int allVideos = getVideos4Plan(courseIds);
            // 查询学习计划下已观看视频记录
            int viewVideos = 0;
            for (Long courseId : courseIds) {
                UsersCourse usersCourse = userCoursesMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                        .eq(UsersCourse::getUserId, userId)
                        .eq(UsersCourse::getCourseId, courseId));
                if (ObjectUtil.isNotNull(usersCourse)) {
                    Integer videos4User = getVideos4User(usersCourse);
                    viewVideos += videos4User;
                }
            }
            // 计算学习计划完成率
            double progress = (allVideos != 0 ? viewVideos * 100.0 / allVideos : 0);
            userPlanVo.setProgress(progress);
            userPlanVos.add(userPlanVo);
        });
        return userPlanVos;
    }

    /**
     * 用户课程列表（按id查询）
     *
     * @param planId
     * @return
     */
    @Override
    public List<UserCourseVo> courseList(Long planId) {
        if (ObjectUtil.isNull(planId)) {
            throw new ServiceException("学习计划id为空");
        }
        // 获取用户Id
        Long userId = LoginHelper.getUserId();
        List<UserCourseVo> userCourseVos = new ArrayList<>();
        // 获取课程信息
        List<PlanCourses> planCourses = planCoursesMapper.selectList(new LambdaQueryWrapper<PlanCourses>()
                .eq(PlanCourses::getPlanId, planId));
        planCourses.forEach(planCourse -> {
            UserCourseVo userCourseVo = new UserCourseVo();
            // 查询课程信息
            Course course = courseMapper.selectById(planCourse.getCourseId());
            userCourseVo.setCourseId(course.getCourseId());
            userCourseVo.setCourseName(course.getCourseTitle());
            userCourseVo.setCourseCover(course.getCourseCover());
            userCourseVo.setBeginData(course.getCourseBeginDate());
            userCourseVo.setEndData(course.getCourseEndDate());
            // 获取每个课程的学习进度
            UsersCourse usersCourse = userCoursesMapper.selectOne(new QueryWrapper<UsersCourse>()
                    .eq("user_id", userId)
                    .eq("course_id", course.getCourseId()));
            int userVideoCount = 0;
            if (ObjectUtil.isNotNull(usersCourse)) {
                userVideoCount = getVideos4User(usersCourse);
            }
            int videoCount = getVideosCounts(course.getCourseId());
            userCourseVo.setCourseDegree(videoCount == 0 ? 0 : userVideoCount * 100.0 / videoCount);
            userCourseVos.add(userCourseVo);
        });
        return userCourseVos;
    }

    /**
     * 查询章节列表
     *
     * @param courseId
     * @return
     */
    @Override
    public R<List<UserChapterVo>> chapterList(Long courseId) {
        // TODO 判断用户是否允许观看这非公开课程
        // 获取用户Id
        Long userId = LoginHelper.getUserId();
        // 查询课程章节泪飙
        List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId)
                .orderByAsc(Chapter::getChapterLevel));
        List<UserChapterVo> userChapterVos = new ArrayList<>();
        UsersCourse usersCourse = userCoursesMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                .eq(UsersCourse::getUserId, userId)
                .eq(UsersCourse::getCourseId, courseId));
        // 是否已到达正在观看章节
        AtomicBoolean isTry = new AtomicBoolean(false);
        // 是否已到达当前视频
        AtomicBoolean isToVideo = new AtomicBoolean(false);
        chapters.forEach(chapter -> {
            UserChapterVo userChapterVo = new UserChapterVo();
            userChapterVo.setChapterId(chapter.getChapterId());
            userChapterVo.setChapterName(chapter.getChapterName());
            // 查询该章节是否完成
            // 章节是否完成
            if (ObjectUtil.isNull(usersCourse)) {
                // 未观看
                userChapterVo.setIsFinish(0);
            } else if (!usersCourse.getChapterId().equals(chapter.getChapterId())) {
                // 章节id不相等，说明该章节已看完，章节完成度100%
                if (!isTry.get()) {
                    userChapterVo.setIsFinish(1);
                } else {
                    userChapterVo.setIsFinish(0);
                }
            } else {
                // 章节id相等，已到达正在观看章节的id
                isTry.set(true);
                // 该章节是否观看完
                if (usersCourse.getChapterFinish() == 1) {
                    userChapterVo.setIsFinish(1);
                } else {
                    // 计算该章节视频总时长，与已观看时长
                    userChapterVo.setIsFinish(0);
                }
            }
            // 章节下视频数目
            userChapterVo.setVideoList(videoList(chapter.getChapterId(), usersCourse, isToVideo));
            userChapterVos.add(userChapterVo);
        });
        return R.ok(userChapterVos);
    }


    private List<UserVideoVo> videoList(Long chapterId, UsersCourse usersCourse, AtomicBoolean isToVideo) {
        // 查询章节视频
        List<ChapterVideo> chapterVideos = chapterVideoMapper.selectList(new LambdaQueryWrapper<ChapterVideo>()
                .eq(ChapterVideo::getChapterId, chapterId)
                .orderByAsc(ChapterVideo::getLevel));

        List<UserVideoVo> userVideoVos = new ArrayList<>();

        chapterVideos.forEach(chapterVideo -> {
            UserVideoVo userVideoVo = new UserVideoVo();
            userVideoVo.setIsForward(chapterVideo.getIsForward());
            userVideoVo.setProblemPoint(JSONUtil.toList(chapterVideo.getProblems(), UserVideoVo.ProblemPoint.class));
            // 查询视频信息
            Video video = videoMapper.selectById(chapterVideo.getVideoId());
            userVideoVo.setVideoId(video.getVideoId());
            userVideoVo.setVideoUrl(video.getVideoUrl());
            userVideoVo.setVideoName(video.getVideoName());
            // 查询视频是否完成
            if (ObjectUtil.isNull(usersCourse)) {
                userVideoVo.setIsFinish(0);
                userVideoVo.setViewPoint(0);
            } else {
                // 当前视频id是否等于当前章节视频id
                if (usersCourse.getVideoId().equals(chapterVideo.getVideoId())) {
                    isToVideo.set(true);
                    if (usersCourse.getVideoFinish() == 1) {
                        userVideoVo.setIsFinish(1);
                        userVideoVo.setViewPoint(0);
                    } else {
                        userVideoVo.setIsFinish(0);
                        userVideoVo.setViewPoint(usersCourse.getVideoNowDuration());
                    }
                } else {
                    if (isToVideo.get()) {
                        // 当前观看视频以后视频
                        userVideoVo.setIsFinish(0);
                    } else {
                        // 当前观看视频以前视频
                        userVideoVo.setIsFinish(1);
                    }
                    userVideoVo.setViewPoint(0);
                }
            }
            userVideoVos.add(userVideoVo);
        });
        return userVideoVos;
    }

    /**
     * 课程观看历史记录
     *
     * @return
     */
    @Override
    public List<CourseHistoryVo> courseViewHistory(Integer size) {
        if (size.intValue() <= 0) {
            size = 6;
        }
        // 登录用户id
        Long userId = LoginHelper.getUserId();
        List<UsersCourse> usersCourses = userCoursesMapper.selectList(new LambdaQueryWrapper<UsersCourse>()
                .eq(UsersCourse::getUserId, userId)
                .orderByDesc(UsersCourse::getUpdateTime)
                .last("limit " + size));
        List<CourseHistoryVo> courseHistoryVos = new ArrayList<>();
        usersCourses.forEach(usersCourse -> {
            CourseHistoryVo courseHistoryVo = new CourseHistoryVo();
            courseHistoryVo.setCourseId(usersCourse.getCourseId());
            courseHistoryVo.setViewDate(usersCourse.getUpdateTime());
            // 查询课程信息
            Course course = courseMapper.selectById(usersCourse.getCourseId());
            courseHistoryVo.setCourseName(course.getCourseTitle());
            courseHistoryVo.setCourseCover(course.getCourseCover());
            // 查询章节信息
            Chapter chapter = chapterMapper.selectById(usersCourse.getChapterId());
            courseHistoryVo.setChapterId(chapter.getChapterId());
            courseHistoryVo.setChapterName(chapter.getChapterName());
            // 绑定视频id
            courseHistoryVo.setVideoId(usersCourse.getVideoId());
            // 查询课程进度
            Integer videosCounts = getVideosCounts(course.getCourseId());
            Integer videos4User = getVideos4User(usersCourse);
            courseHistoryVo.setViewDegree(videosCounts.intValue() == 0 ? 0 : videos4User * 100.0 / videosCounts);
            courseHistoryVos.add(courseHistoryVo);
        });
        return courseHistoryVos;
    }

    @Override
    public R<CourseHistoryVo> courseViewHistoryById(Long courseId) {
        // 登录用户id
        Long userId = LoginHelper.getUserId();
        UsersCourse usersCourses = userCoursesMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                .eq(UsersCourse::getUserId, userId)
                .eq(UsersCourse::getCourseId, courseId));
        CourseHistoryVo historyVo = new CourseHistoryVo();
        if (ObjectUtil.isNotNull(usersCourses)) {
            historyVo.setCourseId(courseId);
            historyVo.setChapterId(usersCourses.getChapterId());
            historyVo.setVideoId(usersCourses.getVideoId());
        } else {
            // 查询课程详细信息
            Chapter chapter = chapterMapper.selectOne(new LambdaQueryWrapper<Chapter>()
                    .eq(Chapter::getCourseId, courseId)
                    .orderByAsc(Chapter::getChapterLevel)
                    .last("limit 1"));
            if (ObjectUtil.isNotNull(chapter)) {
                ChapterVideo chapterVideo = chapterVideoMapper.selectOne(new LambdaQueryWrapper<ChapterVideo>()
                        .eq(ChapterVideo::getChapterId, chapter.getChapterId())
                        .orderByAsc(ChapterVideo::getLevel)
                        .last("limit 1"));
                if (ObjectUtil.isNotNull(chapterVideo)) {
                    historyVo.setCourseId(courseId);
                    historyVo.setChapterId(chapter.getChapterId());
                    historyVo.setVideoId(chapterVideo.getVideoId());
                } else {
                    return R.fail("当前课程章节无视频");
                }
            } else {
                return R.fail("当前课程无视频");
            }
        }
        return R.ok(historyVo);
    }

    /**
     * 上传观看进度
     *
     * @param progressBo
     * @return
     */
    @Transactional
    @Override
    public boolean uploadProgress(CourseProgressBo progressBo) {
        // 获取用户id
        Long userId = LoginHelper.getUserId();
        UsersCourse usersCourse = userCoursesMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                .eq(UsersCourse::getUserId, userId)
                .eq(UsersCourse::getCourseId, progressBo.getCourseId()));
        UsersCourse usersCourse1 = BeanUtil.copyProperties(progressBo, UsersCourse.class);
        // 判断当前视频是否看完，看完将设置视频观看数加一
        // 查询视频观看次数
        Video video = videoMapper.selectById(progressBo.getVideoId());
        Long videoPlayCount = video.getVideoPlayCount();
        if (progressBo.getVideoFinish().intValue() == 0) {
            // 更新视频播放次数
            videoMapper.update(null, new LambdaUpdateWrapper<Video>()
                    .set(Video::getVideoPlayCount, videoPlayCount + 1)
                    .eq(Video::getVideoId, progressBo.getVideoId()));
        } else {
            // 更新视频播放次数与完成播放次数
            Long videoFinishCount = video.getVideoFinishCount();
            videoMapper.update(null, new LambdaUpdateWrapper<Video>()
                    .set(Video::getVideoPlayCount, videoPlayCount + 1)
                    .set(Video::getVideoFinishCount, videoFinishCount + 1)
                    .eq(Video::getVideoId, progressBo.getVideoId()));
        }

        if (ObjectUtil.isNull(usersCourse1.getChapterFinish())) {
            // 推断章节是否完成
            // 查询章节下视频列表，查出最后一个
            ChapterVideo chapterVideo = chapterVideoMapper.selectOne(new LambdaQueryWrapper<ChapterVideo>()
                    .eq(ChapterVideo::getChapterId, usersCourse1.getChapterId())
                    .orderByDesc(ChapterVideo::getLevel)
                    .last("limit 1"));
            if (usersCourse1.getVideoId().equals(chapterVideo.getVideoId())
                    && usersCourse1.getVideoFinish().intValue() == 1) {
                usersCourse1.setChapterFinish(1);
            } else {
                usersCourse1.setChapterFinish(0);
            }
        }
        // 绑定用户id
        usersCourse1.setUserId(userId);
        if (ObjectUtil.isNotNull(usersCourse)) {
            // 更新
            usersCourse1.setId(usersCourse.getId());
            return userCoursesMapper.updateById(usersCourse1) > 0;
        } else {
            // 插入
            return userCoursesMapper.insert(usersCourse1) > 0;
        }
    }

    @Override
    public UserVideoVo videoByVideoId(Long courseId, Long chapterId, Long videoId) {
        UserVideoVo userVideoVo = new UserVideoVo();
        ChapterVideo chapterVideo = chapterVideoMapper.selectOne(new LambdaQueryWrapper<ChapterVideo>()
                .eq(ChapterVideo::getChapterId, chapterId)
                .eq(ChapterVideo::getVideoId, videoId));
        userVideoVo.setIsForward(chapterVideo.getIsForward());
        userVideoVo.setProblemPoint(JSONUtil.toList(chapterVideo.getProblems(), UserVideoVo.ProblemPoint.class));
        // 查询视频信息
        Video video = videoMapper.selectById(chapterVideo.getVideoId());
        userVideoVo.setVideoId(video.getVideoId());
        userVideoVo.setVideoUrl(video.getVideoUrl());
        userVideoVo.setVideoName(video.getVideoName());
        // 获取用户id
        Long userId = LoginHelper.getUserId();
        // 获取课程记录
        UsersCourse usersCourse = userCoursesMapper.selectOne(new LambdaQueryWrapper<UsersCourse>()
                .eq(UsersCourse::getUserId, userId)
                .eq(UsersCourse::getCourseId, courseId));
        if (ObjectUtil.isNull(usersCourse)) {
            userVideoVo.setIsFinish(0);
            userVideoVo.setViewPoint(0);
        } else {
            if (usersCourse.getChapterId().equals(chapterId)) {
                // 当前视频id是否等于当前章节视频id
                if (usersCourse.getVideoId().equals(videoId)) {
                    if (usersCourse.getVideoFinish() == 1) {
                        userVideoVo.setIsFinish(1);
                        userVideoVo.setViewPoint(0);
                    } else {
                        userVideoVo.setIsFinish(0);
                        userVideoVo.setViewPoint(usersCourse.getVideoNowDuration());
                    }
                } else {
                    // 获取视频的级别
                    Integer level = chapterVideo.getLevel();
                    // 历史记录中视频级别
                    if (chapterVideoMapper.selectOne(new LambdaQueryWrapper<ChapterVideo>()
                            .eq(ChapterVideo::getChapterId, usersCourse.getChapterId())
                            .eq(ChapterVideo::getVideoId, usersCourse.getVideoId()))
                            .getLevel() > level) {
                        userVideoVo.setIsFinish(1);
                    } else {
                        userVideoVo.setIsFinish(0);
                    }
                    userVideoVo.setViewPoint(0);
                }
            } else {
                // 获取记录下章节信息
                Chapter chapter1 = chapterMapper.selectById(usersCourse.getChapterId());
                // 获取当前章节等级
                Chapter chapter2 = chapterMapper.selectById(chapterId);
                if (chapter1.getChapterLevel() > chapter2.getChapterLevel()) {
                    // 观看记录之前的章节
                    userVideoVo.setIsFinish(1);
                } else {
                    // 观看记录之后的章节
                    userVideoVo.setIsFinish(0);
                }
                userVideoVo.setViewPoint(0);
            }
        }
        return userVideoVo;
    }

    @Override
    public List<UserResVo> courseResList(Long courseId, Integer resType) {
        if (ObjectUtil.isNotNull(resType) && (resType < 1 || resType > 5)) {
            throw new ServiceException("文件类型不符合");
        }
        List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId)
                .orderByAsc(Chapter::getChapterLevel));
        List<UserResVo> userResVos = new ArrayList<>();
        chapters.forEach(chapter -> {
            // 查询章节下资源
            List<ChapterRes> chapterRes = chapterResMapper.selectList(new LambdaQueryWrapper<ChapterRes>()
                    .eq(ChapterRes::getChapterId, chapter.getChapterId())
                    .orderByDesc(ChapterRes::getLevel));
            chapterRes.forEach(cr -> {
                UserResVo userResVo = new UserResVo();
                // 获取资源信息
                Res res = resMapper.selectOne(new LambdaQueryWrapper<Res>()
                        .eq(Res::getResId, cr.getResId())
                        .eq(ObjectUtil.isNotNull(resType), Res::getResType, resType));
                if (ObjectUtil.isNotNull(res)) {
                    userResVo.setResId(res.getResId());
                    userResVo.setResName(res.getResName());
                    userResVo.setResUrl(res.getResUrl());
                    userResVo.setResType(res.getResType());
                    userResVo.setResSize(res.getResSize());
                    userResVos.add(userResVo);
                }
            });
        });
        return userResVos;
    }

    /**
     * 公开课程列表
     */
    @Override
    public TableDataInfo<UserCourseVo> pubCourseList(SearchEntity search, PageQuery pageQuery) {
        Page<UserCourseVo> userCourseVoPage = courseMapper.selectUserCourseList(search, pageQuery.build());
        return TableDataInfo.build(userCourseVoPage);
    }

    /**
     * 查询附件资源列表详细信息
     */
    @Override
    public List<UserResVo> resListByIds(List<Long> resIds) {
        List<Res> res = resMapper.selectList(new LambdaQueryWrapper<Res>()
                .in(Res::getResId, resIds));
        if (ObjectUtil.isNull(res)) {
            return null;
        }
        return BeanUtil.copyToList(res, UserResVo.class);
    }


    /**
     * 查询课程下总视频数
     */
    private Integer getVideosCounts(Long courseId) {
        int countVideo = 0;
        // 获取每个课程下的章节数
        List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, courseId));
        // 获取每个章节下的视频数
        for (Chapter chapter : chapters) {
            countVideo += chapter.getChapterVideoCount();
        }

        return countVideo;
    }

    /**
     * 获取某个用户某个视频已观看视频数
     */
    private Integer getVideos4User(UsersCourse userCourse) {
        int videoCount = 0;
        // 获取章节数
        List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>()
                .eq(Chapter::getCourseId, userCourse.getCourseId())
                .orderByAsc(Chapter::getChapterLevel));
        for (int i = 0; i < chapters.size(); i++) {
            if (!chapters.get(i).getChapterId().equals(userCourse.getChapterId())) {
                // 说明未到该章节，获取章节视频
                Integer chapterVideoCount = chapterMapper.selectById(chapters.get(i)
                        .getChapterId()).getChapterVideoCount();
                videoCount += chapterVideoCount;
            } else {
                if (userCourse.getChapterFinish() == 1) {
                    // 该章节看完
                    // 说明已到该章节，获取章节视频
                    Integer chapterVideoCount = chapterMapper.selectById(chapters.get(i)
                            .getChapterId()).getChapterVideoCount();
                    videoCount += chapterVideoCount;
                    return videoCount;
                } else {
                    // 章节未看完
                    List<ChapterVideo> chapterVideos = chapterVideoMapper.selectList(new LambdaQueryWrapper<ChapterVideo>()
                            .eq(ChapterVideo::getChapterId, chapters.get(i).getChapterId())
                            .orderByAsc(ChapterVideo::getLevel));
                    int count = 0;
                    for (ChapterVideo chapterVideo : chapterVideos) {
                        if (!userCourse.getVideoId().equals(chapterVideo.getVideoId())) {
                            count++;
                        } else {
                            if (userCourse.getVideoFinish() == 1) {
                                // 该视频已看完
                                count++;
                            }
                            videoCount += count;
                            return videoCount;
                        }
                    }
                }
            }
        }
        return videoCount;
    }

    /**
     * 获取某个学习计划下的视频数
     */
    private Integer getVideos4Plan(List<Long> courseIds) {
        int counts = 0;
        for (Long courseId : courseIds) {
            counts += getVideosCounts(courseId);
        }
        return counts;
    }
}
